package main

import (
	"encoding/json"
	"fmt"
	"unsafe"
)

// Array 1
func function01() {
	const lenA = 2
	var a [lenA + 1]int // 常量表达式定义数组长度
	// var lenB = 3
	// b := [lenB]int{} 错误！变量不可用于定义数组长度

	var b = [1]bool{true}                   // 基本初始化
	var c [2]string = [...]string{"A", "B"} // 省略号自行推断数组长度
	d := [...]int{1: -1, 3: 5}              // 索引值初始化

	fmt.Println(a, b, c, d) // [0 0 0] [true] [A B] [0 -1 0 5]

	// 第一维可自动推导长度
	citys := [...][3]string{
		{"北京", "上海", "广州"},
		{"重庆", "湖南", "武汉"},
	}
	fmt.Println(citys) // [[北京 上海 广州] [重庆 湖南 武汉]]

	// 二维数组遍历
	for _, v1 := range citys {
		for _, city := range v1 {
			fmt.Print(city)
		}
	} // 北京上海广州重庆湖南武汉
}

// Array 2
func function02() {
	a := [...]int{1, 2}
	b := a
	b[0] = 3
	fmt.Println(a, b) // [1 2] [3 2]

	for i, length := 0, len(a); i < length; i++ {
		fmt.Printf("%v ", a[i])
	} // 1 2
	fmt.Println()

	// 同类型且内部元素可比较，那么可以使用 == 和 != 比较两个数组
	fmt.Printf("%#v %#v %T %T %t %t\n", a, b, a, b, b == a, b != a) // [2]int{1, 2} [2]int{3, 2} [2]int [2]int false true
}

// Slice 1
func function03() {
	a := [5]int{1, 2, 3, 4: -1} // 1 2 3 0 -1
	strA := "Hello Golang"
	ptrStrA := new(string)
	ptrStrA = &strA

	sliceA := a[1:5]                             // 基于数组
	sliceStrA := strA[6:]                        // 基于字符串
	slicePtrStrA := (*ptrStrA)[:5]               // 基于字符串指针
	fmt.Println(sliceA, sliceStrA, slicePtrStrA) // [2 3 0 -1] Golang Hello

	sliceB := sliceA[2:]           // 基于切片
	fmt.Println(sliceB)            // [0 -1]
	sliceB[0] = -2                 // 引用类型
	fmt.Println(a, sliceA, sliceB) // [1 2 3 -2 -1] [2 3 -2 -1] [-2 -1]
}

// Slice 2
func function04() {
	a := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
	fmt.Println(a, len(a), cap(a)) // [0 1 2 3 4 5 6 7] 8 8

	sliceA1 := a[1:5]
	fmt.Println(sliceA1, len(sliceA1), cap(sliceA1)) // [1 2 3 4] 4 7
	sliceA2 := a[1:5:7]
	fmt.Println(sliceA2, len(sliceA2), cap(sliceA2)) // [1 2 3 4] 4 6

	b := make([]int, 1, 4)
	b = append(b, 2, 3)
	fmt.Println(b) // [0 2 3]
}

// Slice 3
func function05() {
	var s1 []int // nil 切片，不仅没大小容量，且不指向任何底层数组
	s2 := []int{}
	s3 := make([]int, 0) // s2、s3 都是 empty 切片，没大小容量，但指向一个特殊的内存地址 zerobase - 所有 0 字节分配的基地址

	fmt.Println(len(s1), len(s2), len(s3), cap(s1), cap(s2), cap(s3)) // 0 0 0 0 0 0
	fmt.Println(s1 == nil, s2 == nil, s3 == nil)                      // true false false
	fmt.Printf("%#v %#v %#v\n", s1, s2, s3)                           // []int(nil) []int{} []int{}

	// fmt.Println(s1 == s2) // 切片之间不允许直接使用 == 比较，唯一可以和 nil 进行比较
}

// Slice 4
func function06() {
	var a []int // nil 切片
	a = append(a, 2, 3, 4)
	fmt.Println(a, len(a), cap(a)) // [2 3 4] 3 3
}

// Slice 5
func function07() {
	a := []int{1, 2, 3}
	var b = make([]int, len(a), len(a))
	copy(b, a)        // 深拷贝
	fmt.Println(a, b) // [1 2 3] [1 2 3]
	b[0] = -1
	fmt.Println(a, b) // [1 2 3] [-1 2 3]
}

// Slice 6
func function08() {
	a := []int{1, 2, 3}
	b := append(a[:1], a[2:]...)

	fmt.Println(b) // [1 3]

	copy(a[1:], a[2:])
	fmt.Println(a[:len(a)-1]) // [1 3]
}

// Map 1
func function09() {
	var a map[string]int
	b := map[string]int{}
	c := make(map[string]int)
	fmt.Println(a == nil, b == nil, c == nil) // true false false
}

// Map 2
func function10() {
	b := map[string]int{
		"周一": 1,
		"周二": 2,
	}
	b["周三"] = 3

	// 遍历 map
	for k, v := range b {
		fmt.Println(k, v)
	}

	// 取值第二个返回值，表示是否存在该元素
	if v, ok := b["周二"]; ok {
		fmt.Println(v)
	}
}

// Map 3
func function11() {
	m := make(map[int]string, 4)
	m[1] = "Python"
	m[2] = "Go"
	m[3] = "Lua"

	for _, v := range m {
		fmt.Println(v)
	} // Python Go Lua

	delete(m, 2)

	for _, v := range m {
		fmt.Println(v)
	} // Python Lua
}

// 返回值命名
func function12(x, y int) (ret int) {
	ret = x + y
	return
}

// 多返回值
func function13(a int, b int) (int, int) {
	return b, a
}

// 变参函数
func function14(nums ...int) int {
	sum := 0
	for _, v := range nums {
		sum = sum + v
	}
	return sum
}

func function14_1() {
	ret := function14([]int{1, 2, 3}...)
	fmt.Print(ret) // 6
}

// 函数参数
func function15(a, b int, f func(int, int) int) {
	f(a, b)
	return
}

// 函数变量,匿名函数
func function16() {
	add := func(a, b int) int {
		return a + b
	}
	function15(1, 2, add)
}

// 函数返回值,函数闭包
func function17() func(int) int {
	y := 1
	return func(x int) int {
		return x + y
	}
}

// defer
func function18() {
	f1 := func() {
		fmt.Print(1)
	}

	f2 := func() {
		defer f1()
		fmt.Print(2)
	}

	defer func() {
		fmt.Print(3)
		defer f2()
	}() // 321
	return
}

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}

func function19() {
	x := 1
	y := 2
	defer calc("AA", x, calc("A", x, y))
	x = 10
	defer calc("BB", x, calc("B", x, y))
	y = 20
}

// 递归
func function20() {
	var dfs func(int) int

	dfs = func(x int) int {
		if x > 3 {
			return 3
		}
		return x + dfs(x+1)
	}

	ret := dfs(1)
	fmt.Print(ret) // 1+2+3+3 == 9
}

// panic, recover
func function21() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("recover err:", err)
		}
	}() // recover err: function error!

	func() {
		panic("function error!")
	}()

	fmt.Println("After panic") // 不会执行
}

// 类型定义，类型别名
func function22() {
	type MyInt int // 类型定义
	var a int = 1
	var b MyInt
	b = MyInt(a)          // 必须显示转换
	fmt.Printf("%T\n", b) // main.MyInt

	type MyFloat = float32 // 类型别名
	var A float32 = 0.1
	var B MyFloat
	B = A                 // 只是别名，本质同属一个类型
	fmt.Printf("%T\n", B) // float32
}

// 结构体
type Info struct {
	Email string
	Phone string
}

type Person struct {
	ID      int64 `json:"id" form:"id"` // tag 标签
	Name    string
	Contact Info
}

type Node struct {
	val  int
	next *Node
}

func function23() {
	a := Info{
		Email: "123@163.com",
		Phone: "123456",
	}

	// 结构体简单，按顺序初始化
	b := Info{
		"456@163.com",
		"987654",
	}
	fmt.Printf("%T %T\n", a, Person{}) // main.Info main.Person
	fmt.Println(a, b)                  // {123@163.com 123456} {456@163.com 987654}
}

func function24() {
	a := struct {
		x, y int
	}{
		1, 2,
	}
	fmt.Println(a) // {1 2}
}

func function25() {
	fmt.Println(unsafe.Sizeof(struct{}{})) // 0

	type structA struct {
		A int8     // 1 byte
		B struct{} // 0 byte
	}
	var a structA

	fmt.Println(unsafe.Sizeof(a)) // 2
}

func function26() {
	type structA struct {
		A int32    // 4 byte
		B struct{} // 0 byte
	}
	var a structA

	fmt.Println(unsafe.Sizeof(a), unsafe.Alignof(a)) // 8 4
}

// 结构体嵌套
func function27() {
	type Student struct {
		Name string
		Info // 结构体嵌套
	}

	var a Student

	a = Student{
		Name: "Cauchy",
		Info: Info{
			Email: "123@163.com",
			Phone: "123456",
		},
	}
	fmt.Println(a.Name, a.Email, a.Phone) // Cauchy 123@163.com 123456
}

// JSON
func function28() {
	type Phone struct {
		Price int    `json:"price"`
		Name  string `json:"name"`
	}

	s := Phone{
		Price: 3888,
		Name:  "小米",
	}

	s1, _ := json.Marshal(s) // JSON 序列化
	fmt.Printf("%s\n", s1)   // {"price":3888,"name":"小米"}

	var a Phone
	_ = json.Unmarshal(s1, &a) // JSON 反序列化
	fmt.Println(a)             // {3888 小米}
}

// 自定义结构体构造函数
func NewInfo() *Info {
	return &Info{
		Email: "123@163.com",
		Phone: "123456",
	}
}

func function29() {
	a := NewInfo()
	fmt.Println(a) // &{123@163.com 123456}
}

type Course struct {
	Name  string
	Score int8
}

// 值接收者
func (c Course) getName() string {
	return c.Name
}

// 指针接收者
func (c *Course) setScore(score int8) {
	c.Score = score
}

type Math struct {
	People int8
	Course
}

func function30() {
	m := Math{
		People: 36,
		Course: Course{
			Name:  "math",
			Score: 100,
		},
	}
	fmt.Println(m.Course.Name, m.Score) // math 100
	m.setScore(120)
	fmt.Println(m.Course.getName(), m.Course.Score) // math 120
}

type MyBool bool

func (m MyBool) SayType() {
	fmt.Printf("%T\n", m)
}

//type PtrMyBool *MyBool
//func (p PtrMyBool) SayType()  {}  // *MyBool' is a pointer type

func function31() {
	var a MyBool
	a.SayType() // main.MyBool
}

func main() {
}

func init() {
	fmt.Println("main init")
}
